package base.service.impl;

import base.pojo.Account;
import base.service.IAccountService;
import base.service.IAliPayService;
import business.pojo.RechargeOnline;
import business.service.IAccountFlowService;
import business.service.IRechargeOnlineService;
import com.alipay.api.AlipayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.demo.trade.config.Configs;
import com.alipay.demo.trade.model.ExtendParams;
import com.alipay.demo.trade.model.GoodsDetail;
import com.alipay.demo.trade.model.builder.AlipayTradePrecreateRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FPrecreateResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.alipay.demo.trade.service.impl.AlipayTradeServiceImpl;
import com.alipay.demo.trade.utils.ZxingUtils;
import common.Const;
import common.ServerResponse;
import common.UserContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class AliPayServiceImpl implements IAliPayService
{
    private static Log log = LogFactory.getLog(AliPayServiceImpl.class);

    @Autowired
    IRechargeOnlineService  iRechargeOnlineService  ;
    @Autowired
    IAccountFlowService     iAccountFlowService     ;
    @Autowired
    IAccountService         iAccountService         ;

    public ServerResponse pay(String money, String path)
    {
        // (必填) 商户网站订单系统中唯一订单号，64个字符以内，只能包含字母、数字、下划线，
        // 需保证商户系统端不能重复，建议通过数据库sequence生成，
        String outTradeNo = "p2p" + System.currentTimeMillis()
                + (long) (Math.random() * 10000000L);

        // (必填) 订单标题，粗略描述用户的支付目的。如“xxx品牌xxx门店当面付扫码消费”
        String subject = "P2P网贷系统扫描支付";

        // (必填) 订单总金额，单位为元，不能超过1亿元
        // 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
        String totalAmount = money;

        // (可选) 订单不可打折金额，可以配合商家平台配置折扣活动，如果酒水不参与打折，则将对应金额填写至此字段
        // 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
        String undiscountableAmount = "0";

        // 卖家支付宝账号ID，用于支持一个签约账号下支持打款到不同的收款账号，(打款到sellerId对应的支付宝账号)
        // 如果该字段为空，则默认为与支付宝签约的商户的PID，也就是appid对应的PID
        String sellerId = "";

        // 订单描述，可以对交易或商品进行一个详细地描述，比如填写"购买商品2件共15.00元"
        String body = "支付宝在线充值:"+money+"元";

        // 商户操作员编号，添加此参数可以为商户操作员做销售统计
        String operatorId = "test_operator_id";

        // (必填) 商户门店编号，通过门店号和商家后台可以配置精准到门店的折扣信息，详询支付宝技术支持
        String storeId = "test_store_id";

        // 业务扩展参数，目前可添加由支付宝分配的系统商编号(通过setSysServiceProviderId方法)，详情请咨询支付宝技术支持
        ExtendParams extendParams = new ExtendParams();
        extendParams.setSysServiceProviderId("2088100200300400500");

        // 支付超时，定义为120分钟
        String timeoutExpress = "120m";

        // 商品明细列表，需填写购买商品详细信息，
        List<GoodsDetail> goodsDetailList = new ArrayList<GoodsDetail>();
        // 创建一个商品信息，参数含义分别为商品id（使用国标）、名称、单价（单位为分）、数量，如果需要添加商品类别，详见GoodsDetail
        GoodsDetail goods1 = GoodsDetail.newInstance(outTradeNo, "支付宝在线充值", new BigDecimal(money).longValue(), 1);
        // 创建好一个商品后添加至商品明细列表
        goodsDetailList.add(goods1);
        // 创建扫码支付请求builder，设置请求参数
        AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
                .setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo)
                .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
                .setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
                .setTimeoutExpress(timeoutExpress)
                .setNotifyUrl("http://yiyun.s1.natapp.cc/alipay_callback.do")//回调地址
                .setGoodsDetailList(goodsDetailList);

        //一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
        Configs.init("zfbinfo.properties");
        AlipayTradeService tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
        AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                log.info("支付宝预下单成功: )");

                AlipayTradePrecreateResponse response = result.getResponse();
                dumpResponse(response);

                File folder = new File(path);
                if(!folder.exists())
                {
                    folder.setWritable(true);
                    folder.mkdirs();
                }
                String qrPath = String.format(path+"/qr-%s.png",response.getOutTradeNo());
                String qrFileName = String.format("qr-%s.png",response.getOutTradeNo());
                ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);
                RechargeOnline rechargeOnline = new RechargeOnline();
                rechargeOnline.setAmount(new BigDecimal(money));
                rechargeOnline.setApplier(UserContext.getCurrentUser());
                rechargeOnline.setRechargeDate(new Date());
                rechargeOnline.setTradeCode(response.getOutTradeNo());
                rechargeOnline.setQrPath(qrFileName);
                ServerResponse sr=iRechargeOnlineService.apply(rechargeOnline);
                log.info("filePath:" + qrPath);
                if(sr.getStatus()==0){
                return ServerResponse.createBySuccess(rechargeOnline);
                }
                return ServerResponse.createByErrorMsg("支付宝下单失败");
            case FAILED:
                log.error("支付宝预下单失败!!!");
                return ServerResponse.createByErrorMsg("支付宝预下单失败!!!");
            case UNKNOWN:
                log.error("系统异常，预下单状态未知!!!");
                return ServerResponse.createByErrorMsg("系统异常，预下单状态未知!!!");
            default:
                log.error("不支持的交易状态，交易返回异常!!!");
                return ServerResponse.createByErrorMsg("不支持的交易状态，交易返回异常!!!");
        }
    }

    public ServerResponse aliCallBack(Map<String, String> params) throws Exception {
        System.err.println("支付宝正在回调");
        String tradeCode = params.get("out_trade_no");
        RechargeOnline r = iRechargeOnlineService.getRechargeOnlineByTradeCode(tradeCode);
        if(r==null)
        {
            return ServerResponse.createByErrorMsg("订单不存在")                     ;
        }
        if(r.getState() >= Const.PAY_SUCCESS )
        {
            return ServerResponse.createBySuccess("支付宝重复调用")                  ;
        }
        String tradeNo   = params.get("trade_no")                                   ;
        String status    = params.get("trade_status")                               ;
        if(Const.aliPayCallBack.TRADE_STATUS_TRADE_SUCCESS.equals(status))
        {
            r.setState(Const.PAY_SUCCESS)                                           ;
            r.setTradeNO(tradeNo)                                                   ;
            Account account = iAccountService.get(r.getApplier().getId())           ;
            account.setUsableAmount(account.getUsableAmount().add(r.getAmount()))   ;
            iAccountFlowService.rechargeFlow(r,account)                             ;
            iRechargeOnlineService.update(r)                                        ;
            iAccountService.update(account)                                         ;
        }
        return ServerResponse.createBySuccess()                                     ;
    }

    public ServerResponse queryPay(String tradeCode)
    {
        RechargeOnline r = iRechargeOnlineService.getRechargeOnlineByTradeCode(tradeCode);
        if(r==null)
        {
            return ServerResponse.createByErrorMsg("用户没有该充值记录");
        }
        if(r.getState() == Const.PAY_SUCCESS )
        {
            return  ServerResponse.createBySuccessMsg("支付成功");
        }
        return ServerResponse.createByError();
    }

    // 简单打印应答
    private void dumpResponse(AlipayResponse response) {
        if (response != null) {
            log.info(String.format("code:%s, msg:%s", response.getCode(), response.getMsg()));
            if (StringUtils.isNotEmpty(response.getSubCode())) {
                log.info(String.format("subCode:%s, subMsg:%s", response.getSubCode(),
                        response.getSubMsg()));
            }
            log.info("body:" + response.getBody());
        }
    }
}
